package com.sixbro.websocket.netty.server;

import com.sixbro.websocket.netty.common.ChatConstants;
import com.sixbro.websocket.netty.module.UserInfo;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.RandomAccessFile;
import java.util.List;
import java.util.Map;

/**
 * @Author: Mr.Lu
 * @Date: 2020/9/19 15:28
 */
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    private static final Logger logger = LoggerFactory.getLogger(HttpRequestHandler.class);

    private final String webUri;
    private final String INDEX = "E:\\oworkspace\\test\\src\\main\\webapp\\index.html";

    public HttpRequestHandler(String webUri) {
        this.webUri = webUri;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        logger.info("===========> {}, {}", webUri, request.uri());

        String uri = StringUtils.substringBefore(request.uri(), "?");
        if (webUri.equalsIgnoreCase(uri)) {
            // 获取webSocket参数
            QueryStringDecoder query = new QueryStringDecoder(request.uri());
            Map<String, List<String>> parameters = query.parameters();

            List<String> tokens = parameters.get("token");

            // 根据参数保存当前登录对象, 并把该token加入到channel中
            if (!CollectionUtils.isEmpty(tokens)) {
                String token = tokens.get(0);
                ChatConstants.addOnlines(token, new UserInfo(token));
                ctx.channel().attr(ChatConstants.CHANNEL_TOKEN_KEY).getAndSet(token);
            }

            request.setUri(uri);
            ctx.fireChannelRead(request.retain());
        } else {
            if (HttpUtil.is100ContinueExpected(request)) {
                send100ContinueExpected(ctx);
            }

            RandomAccessFile file = new RandomAccessFile(INDEX, "r");
            HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");

            boolean keepAlive = HttpUtil.isKeepAlive(request);
            if (keepAlive) {
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, file.length());
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            }
            ctx.write(response);

            if (ctx.pipeline().get(SslHandler.class) == null) {
                ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
            } else {
                ctx.write(new ChunkedNioFile(file.getChannel()));
            }

            ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
            if (!keepAlive) {
                future.addListener(ChannelFutureListener.CLOSE);
            }

            file.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    private void send100ContinueExpected(ChannelHandlerContext ctx) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONFLICT);
        ctx.writeAndFlush(response);
    }
}
